
#include <sys/socket.h>	/* socket AF_UNIX SOCK_STREAM sockaddr bind accept */
#include <sys/un.h>		/* sockaddr_un */
#include <stdio.h>		/* perror printf */
#include <string.h>		/* strcpy */
#include <unistd.h>		/* unlink read write close */
#include "comm.h"

#define SERVER_STRING "server received"

static char recv_buf[RECV_BUF_SIZE];

int main()
{
	struct sockaddr_un srv_addr;	/* 服务器域套接字地址 */
	struct sockaddr_un clt_addr; 
	int listen_fd, connect_fd;
	int ret;
	
	/* 打开一个套接字，地址族协议：本地IPC通信（非ipv4或ipv4），
	   套接字类型：流，使用的协议：无（非TCP或UDP） */
	listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (listen_fd < 0) {
		perror("socket");
		return -1;
	}

	srv_addr.sun_family = AF_UNIX;	/* 本机IPC通信 */
	strcpy(srv_addr.sun_path, SOCKET_FILE);	/* 使用虚拟内存文件 */
	
	unlink(SOCKET_FILE);	/* 绑定前先取消本地内存文件链接，防止绑定报错 */
	/* 绑定套接字和协议，使用本地内存文件 */
	ret = bind(listen_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
	if (ret < 0) {
		perror("bind");
		goto exit1;
	}

#define LISTEN_MAX_NUM 8	/* 允许监听但还未链接的链路总数 */
	/* 监听链路 */
	ret = listen(listen_fd, LISTEN_MAX_NUM);
	if (ret < 0) {
		perror("listen");
		goto exit1;
	}
	printf("waitting for client connect...\n");

	int clt_addr_len = sizeof(clt_addr); 
	/* 等待客户端握手连接，如果客户端一直没连接，则会阻塞在这里 */
	connect_fd = accept(listen_fd, (struct sockaddr *)&clt_addr, &clt_addr_len);
	if (ret < 0) {
		perror("accept");
		goto exit1;
	}

	printf("waitting for client send data...\n");

	/* 收发收据 */
	int len;
	while (1) {
		/* 按期望的最大长度进行读取，返回实际读到的长度，
		   没读到数据会一直阻塞住，想要不阻塞需要额外添加pselect函数；
		   read和write函数可以直接用recv和send函数来替换*/
		len = read(connect_fd, recv_buf, sizeof(recv_buf));
		if (len > 0) {
			recv_buf[len] = '\0';
			printf("client-->server[%d]: %s\n", len, recv_buf);
			write(connect_fd, SERVER_STRING, sizeof(SERVER_STRING));
			if (recv_buf[0] == 'e')	/* 自定义一个退出消息 */
				goto exit2;
		}
	}

exit2:
	/* 关闭连接 */
	close(connect_fd);

exit1:
	unlink(SOCKET_FILE);
	/* 关闭套接字 */
	close(listen_fd);
	
	return 0;
}
